/**
 * 检查代理服务器是否可用
 */
var http = require('http'),
    request = require('request'),
    zlib = require('zlib'),
    net = require('net'),
    Socket = net.Socket,
    App = require("../common/App.js"),
    Q = require("q");

var Util = require("../util/util.js");

module.exports = new CheckProxy();

function CheckProxy(){
    //单例模式
    if(typeof arguments.callee.instance === "object"){
        return arguments.callee.instance;
    }

    this.resTimeout = 2000;//响应设置超时时间
    this.resBodyTimeout = 5000;//响应设置超时时间
    this.resBodyMd5 = 'd8400ed485cf9d98bfe5c60e398eac19';
    this.resBodyOptions = {
        proxy:"http://localhost:8080",
        url:'http://www.baidu.com/cache/global/img/gs.gif',
        //url:'http://www.baidu.com/s?wd=sem',
        //url:"http://localhost/js.html",
        timeout:this.resBodyTimeout,
        encoding:null,
            headers:{
            'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            'Accept-Charset':'GBK,utf-8;q=0.7,*;q=0.3',
            'Accept-Encoding':'gzip',
            'Accept-Language':'zh-CN,zh;q=0.8',
            'Cache-Control':'max-age=0',
            'Connection':'keep-alive',
            'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11'
        }
    };
    this.checkThread = 0;
    arguments.callee.instance = this;
}
/**
 * 检测开始
 * @param proxy ProxyInfo
 */
CheckProxy.prototype.check = function(proxy){
    var that = this;

    proxy.runid = Util.s8();
    this.checkThread++;

    return this.checkIpAndPortStatus(proxy)
        .then(
            function(){
                return that.checkResBody(proxy);
            },
            function(err){
                //App.debug(err);
                throw err;
            }
        )
        .then(
            function(){
                that.end(proxy);
                return proxy;
            },
            function(err){
                that.end(proxy);
                throw err;
            }
        );
}

/**
 * 检测结束
 * @param proxy ProxyInfo
 * @param info String
 */
CheckProxy.prototype.end = function(proxy){
    if(proxy.runid!=undefined){
        this.checkThread--;
    }
    delete proxy.runid;
}

/**
 * 判断端口是否开启
 * @param proxy ProxyInfo
 * @param callback
 */
CheckProxy.prototype.checkIpAndPortStatus = function(proxy) {
    var deferred = Q.defer(),
        dateS1 = new Date(),
        socket = new Socket();

    socket.on('connect', function() {
        socket.destroy();
        var dateS2 = new Date();
        proxy.resTime = dateS2.getTime() - dateS1.getTime();
        deferred.resolve()
    });
    socket.setTimeout(this.resTimeout);//设置socket超时时间
    socket.on('timeout', function() {
        socket.destroy();
        deferred.reject(new Error("timeout"));
    });
    socket.on('error', function(err) {
        socket.destroy();
        deferred.reject(err);
    });
    socket.connect(proxy.port, proxy.host);

    return deferred.promise;
};


//检查代理是否可用
/**
 * 用代理访问指定文件，判断返回内容是否正确
 * @param proxy ProxyInfo
 * @param callback
 */
CheckProxy.prototype.checkResBody = function(proxy){
    var deferred = Q.defer(),
    dateS1 = new Date(),
    that = this,
    resBodyOptions = this.resBodyOptions;
    resBodyOptions.proxy = "http://"+proxy.host+":"+proxy.port;

    var resBody = function(buffer_body){
        var hashmsg=Util.md5(buffer_body);
        if(hashmsg.toLowerCase() == that.resBodyMd5.toLowerCase()){
            var dateS2 = new Date();
            proxy.resBodyTime = dateS2.getTime() - dateS1.getTime();
            deferred.resolve(proxy);
        }else{
            deferred.reject(new Error("md5 differ"));
        }
    }

    var req = request.get(resBodyOptions,function(err, res, buffer_body){
        if(err){
            deferred.reject(err);
        }else if(res.statusCode!=200){
            deferred.reject(new Error("http status "+res.statusCode))
        }else{
            if(res.headers['content-encoding']=="gzip"){
                zlib.gunzip(buffer_body,function(err,body){
                    if(!err){
                        resBody(body);
                    }else{
                        deferred.reject(new Error(err));
                    }
                });
            }else{
                resBody(buffer_body);
            }
        }
    });
    return deferred.promise;
}
